//
//  QHMeshView.m
//  QHDrawBitmapMeshMan
//
//  Created by Anakin chen on 2021/5/13.
//

#import "QHMeshView.h"

#include "PerspectiveTransform.hpp"

#define R 10
#define R2 10

@interface QHMeshView ()

@property (nonatomic, strong) NSMutableArray *verts;

@end

@implementation QHMeshView

- (instancetype)init {
    self = [super init];
    if (self) {
        [self p_setup];
    }
    return self;
}

- (void)p_setup {
//    PerspectiveTransform tansform = PerspectiveTransform::quadrilateralToQuadrilateral(75, 67.5, 225, 67.5, 225, 135, 75, 135, 75, 67.5, 150, 67.5, 150, 135, 75, 135);
//    PerspectiveTransform tansform = PerspectiveTransform::quadrilateralToQuadrilateral(0.25, 0.25, 0.75, 0.25, 0.25, 0.5, 0.75, 0.5, 0.25, 0.25, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5);
//    std::tuple<float, float>res = tansform.transform(0.5, 0.5);
//    NSLog(@"end");
}

- (void)drawRect:(CGRect)rect {
    // Drawing code
    if (self.verts == nil || self.verts.count == 0) {
        [self p_initMesh:rect];
    }
    if (!self.showMask) {
        return;
    }
    
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextClearRect(ctx, rect);
    
    NSArray *v = self.verts;
    NSUInteger w = (R + 1) * 2;
    NSUInteger h = v.count / w;
    
    for (int i = 0; i < v.count; i += 2) {
        float x = [v[i] floatValue];
        float y = [v[i + 1] floatValue];
        if (x == 0) {
            CGContextMoveToPoint(ctx, x, y);
        }
        else {
            CGContextAddLineToPoint(ctx, x, y);
        }
    }

    CGContextSetLineWidth(ctx, 1);
    CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1);
    CGContextDrawPath(ctx, kCGPathStroke);
    if (!CGContextIsPathEmpty(ctx)) {
        CGContextClosePath(ctx);
    }
    
    int cc = 0;
    for (int i = 0; i < w; i += 2) {
        for (int j = 0; j < h; j++) {
            float x = [v[i + j * w] floatValue];
            float y = [v[i + 1 + j * w] floatValue];
            if (y == 0) {
                CGContextMoveToPoint(ctx, x, y);
            }
            else {
                CGContextAddLineToPoint(ctx, x, y);
                cc += 1;
            }
        }
    }
    
    CGContextSetLineWidth(ctx, 1);
    CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
    CGContextDrawPath(ctx, kCGPathStroke);
    if (!CGContextIsPathEmpty(ctx)) {
        CGContextClosePath(ctx);
    }
}

- (void)warp2Start:(CGPoint)sp end:(CGPoint)ep {

    NSMutableArray *v = self.verts;
    CGFloat width = self.frame.size.width;
    CGFloat height = self.frame.size.height;
    float w = width/R;
    float h = height/R2;
    // 满足条件的区域半径
    CGFloat r = MAX(w, h) + 0.5/*敏感值*/;

    float dse_x = ep.x - sp.x;
    float des_y = ep.y - sp.y;
    // 求出滑动的直线距离
    float des = sqrtf(dse_x*dse_x + des_y*des_y);

    for (int i = 0; i < v.count; i += 2) {
        float x = [v[i] floatValue];
        float y = [v[i + 1] floatValue];
        
        // 边角区域不修改，保证图像依然是矩形
        if (x == 0 || y == 0 || x == width || y == height) {
            continue;
        }
        else {
            float xx = x - sp.x;
            float yy = y - sp.y;
            // 该点是否在满足的区域，先判断是否在矩形区域，再判断圆形区域
            if (fabsf(xx) <= r && fabsf(yy) <= r) {
                float dxy = sqrtf(xx*xx + yy*yy);
                if (dxy <= r) {
                    // 满足条件的计算出偏移值，并控制偏移值的比例（最大值为半个区域距离）
                    float dr = (r * r - dxy);
                    float e = dr * dr / ((dr + des * des) * (dr + des * des));
                    float tx = MIN(e * dse_x, w/2);
                    float ty = MIN(e * des_y, h/2);
                    v[i] = @(x + tx);
                    v[i + 1] = @(y + ty);
                }
            }
        }
    }
    
    [self p_make4mesh_u];
    
    [self setNeedsDisplay];
    [self layoutIfNeeded];
}

#pragma mark - Private

- (void)p_initMesh:(CGRect)rect {
    NSMutableArray *verts = [NSMutableArray new];
    float bmWidth = rect.size.width;
    float bmHeight = rect.size.height;
    
    NSUInteger w = R;
    NSUInteger h = R2;
    
    // 计算网格在 view 上的实际坐标
    for (int i = 0; i < h + 1; i++) {
        float fy = bmHeight * i / h;
        for (int j = 0; j < w + 1; j++) {
            float fx = bmWidth * j / w;
            [verts addObject:@(fx)];
            [verts addObject:@(fy)];
        }
    }
    
    self.verts = verts;
    [self p_make4mesh_u];
}

// 将网格构成的每一格的四个坐标计算出 GLES 坐标
- (void)p_make4mesh_u {
    CGFloat width = self.frame.size.width;
    CGFloat height = self.frame.size.height;
    NSMutableArray *v = [NSMutableArray new];
    // 转换 GLES 坐标
    for (int i = 0; i < self.verts.count; i++) {
        [v addObject:@([self.verts[i] floatValue] / (i % 2 == 0 ? width : height))];
    }
    float ww = 1.f/R;
    float hh = 1.f/R2;
    int ws = (R + 1) * 2;
    NSMutableArray *aa = [NSMutableArray new];
    for (int j = 0; j < R2; j++) {
        for (int i = 0; i < R; i++) {
//            int idx = i + j * R2;
            // 取出网格的四个角对应坐标的下标 {p1, p2, p3, p4}
            int x = i * 2 + j * ws;
            int xx = x + ws;
            CGPoint p1 = CGPointMake(x, x + 1);
            CGPoint p2 = CGPointMake(p1.x + 2, p1.y + 2);
            CGPoint p4 = CGPointMake(xx, xx + 1);
            CGPoint p3 = CGPointMake(p4.x + 2, p4.y + 2);
            
            // 将可能进过扭曲的网格 -> 透视变换 -> 矩形网格
            PerspectiveTransform tansform = PerspectiveTransform::quadrilateralToQuadrilateral([v[(int)p1.x] floatValue], [v[(int)p1.y] floatValue], [v[(int)p2.x] floatValue], [v[(int)p2.y] floatValue], [v[(int)p3.x] floatValue], [v[(int)p3.y] floatValue], [v[(int)p4.x] floatValue], [v[(int)p4.y] floatValue], (i * ww), (j * hh), (i * ww + ww), (j * hh), (i * ww + ww), (j * hh + hh), (i * ww), (j * hh + hh));
            
            // 计算出透视变换的 矩阵，而 transform 就是转换的公式，此会用于 GLSL 计算出对应的坐标
            [aa addObjectsFromArray:@[@(tansform.a11), @(tansform.a12), @(tansform.a13), @(tansform.a21), @(tansform.a22), @(tansform.a23), @(tansform.a31), @(tansform.a32), @(tansform.a33)]];
        }
    }
    
    _v_mesh = [v copy];
    _h_pt = [aa copy];
}

#pragma mark - Test

- (void)testIdx {
}

@end
